<?php

namespace Xrfg\Api\Trading\Spot\Repositories;

use Illuminate\Redis\Connections\PredisConnection;
use Xrfg\Core\Trading\Spot\Models\Order;

class OrderBook
{
    /**
     * @var PredisConnection
     */
    public $redis;

    /**
     * OrderBook constructor.
     */
    public function __construct()
    {
        $this->redis = app('redis.connection');
    }

    /**
     * Add order to order book.
     *
     * @param Order $order
     */
    public function add(Order $order)
    {
        if (Order::TYPE_MARKET === $order->type) {
            self::addMarket($order);
        } else {
            self::addLimit($order);
        }
    }

    private function addMarket(Order $order)
    {
        $orderbookKey = "etf:orderbook:{$order->symbol}:{$order->side}:{$order->type}";
        $this->redis->lpush($orderbookKey, [$order->id]);
    }

    private function addLimit(Order $order)
    {
        $orderbookKey = "etf:orderbook:{$order->symbol}:{$order->side}:{$order->type}";

        $id = $order->id;
        $price = number_format($order->price, 8, '.', '');
        $number = bcsub($order->number, $order->deal_number);
        $this->redis->eval(config('lua.add'), 1, $orderbookKey, $id, $price, $number);
    }

    public function update(Order $order)
    {
        if (Order::TYPE_MARKET == $order->type) {
            return;
        }

        $orderbookKey = "etf:orderbook:{$order->symbol}:{$order->side}:{$order->type}";

        $id = $order->id;
        $price = number_format($order->price, 8, '.', '');
        $number = bcsub($order->number, $order->deal_number);

        // 订单部分成交
        if (Order::STATUS_NEW == $order->status) {
            $this->redis->eval(config('lua.add'), 1, $orderbookKey, $id, $price, $number);
        }

        // 订单完全成交
        if (Order::STATUS_FILLED == $order->status) {
            $this->redis->eval(config('lua.rem'), 1, $orderbookKey, $id, $price);
        }
    }

    /**
     * Remove order from order book.
     *
     * @param Order $order
     */
    public function remove(Order $order)
    {
        // 市价单
        if (Order::TYPE_MARKET == $order->type) {
            self::removeMarket($order);
        } else {
            self::removeLimit($order);
        }
    }

    private function removeMarket(Order $order): void
    {
        $key = "etf:orderbook:{$order->symbol}:{$order->side}:MARKET";
        $this->redis->lrem($key, 0, $order->id);
    }

    private function removeLimit(Order $order)
    {
        $orderbookKey = "etf:orderbook:{$order->symbol}:{$order->side}:LIMIT";

        $id = $order->id;
        $price = number_format($order->price, 8, '.', '');

        $this->redis->eval(config('lua.rem'), 1, $orderbookKey, $id, $price);
    }

    public function get(string $symbol)
    {
        return $this->redis->eval(config('lua.get'), 0, $symbol);
    }

    /**
     * Get all orders.
     *
     * @param string $symbol
     *
     * @return array
     */
    public function depth(string $symbol)
    {
        $buyKey = "etf:orderbook:{$symbol}:BUY:LIMIT";
        $buys = $this->redis->zrange($buyKey, 0, -1, ['WITHSCORES' => true]);

        $sellKey = "etf:orderbook:{$symbol}:SELL:LIMIT";
        $sells = $this->redis->zrange($sellKey, 0, -1, ['WITHSCORES' => true]);

        return compact('buys', 'sells');
    }
}
